package com.zhentao.service.impl;

import com.alibaba.fastjson.JSON;
import com.zhentao.mapper.TaskinfoLogsMapper;
import com.zhentao.mapper.TaskinfoMapper;
import com.zhentao.model.common.dtos.ResponseResult;
import com.zhentao.model.schedule.dtos.Task;
import com.zhentao.model.schedule.pojos.Taskinfo;
import com.zhentao.model.schedule.pojos.TaskinfoLogs;
import com.zhentao.service.TaskInfoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;


import javax.annotation.Resource;
import java.util.Calendar;
import java.util.Date;
import java.util.Set;

@Service
@Slf4j
public class TaskInfoServiceImpl implements TaskInfoService {

    @Autowired
    private TaskinfoMapper taskInfoMapper;

    @Autowired
    private TaskinfoLogsMapper taskInfoLogsMapper;
    @Resource
    private RedisTemplate<String,Object> redisTemplate;

    @Override
    public ResponseResult addTask(Task taskDto) {
        //添加数据库： 任务表+任务日志表   任务1-任务表   添加日志表【1 什么时候添加的】
        Taskinfo taskInfo = addTaskToDB(taskDto);
        //把任务添加到redis里面  如果小于=当前时候，立即执行-》list  如果是未来要执行的--》zset里面

        taskDto.setTaskId(taskInfo.getTaskId());
        addTaskToRedis(taskDto);
        return ResponseResult.okResult(taskInfo);
    }

    @Override
    public ResponseResult submitCurrentPoll(int type) {
        String listKey = "submit:current:" + type;   //固定就是1
        String task = (String) redisTemplate.opsForList().rightPop(listKey);
        if(StringUtils.isNotBlank(task)){

            Task taskDto= JSON.parseObject(task,Task.class);

            return ResponseResult.okResult(taskDto);
        }
        return null;
    }


    public void addTaskToRedis(Task taskDto) {
     /*   把任务添加到redis里面
          如果任务的执行时间小于=当前时候，立即执行-》list 消息队列里面 --》然后再去消费 写一个定时任务 1s一次，<=当前时间的，立马执行
        如果是未来要执行的--》zset里面   ？ 是所有的数据都放到zset里面吗 ？
                未来5分钟的数据放到zSet里面，也写一个定时任务 1分钟扫描一次，如果zset里面得任务在1分钟之内，放到list里面

        大于5分钟数据怎么办，在数据库里面； 然后写一个定时任务去扫描数据库，5分钟扫描一次，如果数据库里面得任务在5分钟之内，放到zSet里面
    */
        //判断时间是在在5分钟之内，获取到5分钟之后的毫秒值
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MINUTE, 5);
        Long nextTime = calendar.getTimeInMillis();


        //定义key  1.发布文章  "submit:current:1     2.审核  submit:current:2
        String listKey="submit:current:"+taskDto.getTaskType();
        String zsetKey="submit:future:"+taskDto.getTaskType();

        if(taskDto.getExecuteTime()<=System.currentTimeMillis()){
            //如果小于=当前时间  -->list里面

            log.info("放到list{},{}",taskDto,new Date().toLocaleString());
            redisTemplate.opsForList().leftPush(listKey, JSON.toJSONString(taskDto));
        }else if(taskDto.getExecuteTime()<=nextTime){
            //5分钟之内的数据  -->zset里面

            log.info("放到zSet{},{}",taskDto,new Date().toLocaleString());
            redisTemplate.opsForZSet().add(zsetKey,JSON.toJSONString(taskDto),taskDto.getExecuteTime());
        }





    }


    public Taskinfo addTaskToDB(Task dto) {
        //任务表
        Taskinfo taskInfo = new Taskinfo();
        BeanUtils.copyProperties(dto, taskInfo);
        taskInfo.setExecuteTime(new Date(dto.getExecuteTime()));
        taskInfoMapper.insert(taskInfo);

        //任务日志表
        TaskinfoLogs taskInfoLogs = new TaskinfoLogs();
        BeanUtils.copyProperties(taskInfo, taskInfoLogs);
        taskInfoLogs.setVersion(1);
        taskInfoLogs.setStatus(0);
        taskInfoLogsMapper.insert(taskInfoLogs);

        return taskInfo;

    }


    //zet--- list里面
    @Scheduled(cron = "0 */1 * * * ?")
    public void zSetToList() {
        log.info("把zset里面得数据刷新到list里面，{}", new Date().toLocaleString());

        //1.获取到当前要消费的数据
        String zsetKey = "submit:future:" + 1;
        // todo 这里把 Set<Object> 转换成 Set<String>
        Set<Object> tasks =  redisTemplate.opsForZSet().rangeByScore(zsetKey, 0, System.currentTimeMillis());

        //2.把数据放到list里面
        for(Object task:tasks){
            String listKey = "submit:current:" + 1;
            //1.放到list里面
            redisTemplate.opsForList().leftPush(listKey,task);

            //2.把放入list里面得数据从zSet里面删除掉
            redisTemplate.opsForZSet().remove(zsetKey,task);
        }

    }
}